//
//  FancyRestApi.swift
//  Fancyswap
//
//  Created by Francois Gratton on 2015-03-01.
//  Copyright (c) 2015 Jonathan Muschalle. All rights reserved.
//

import Foundation
import UIKit

enum ImageFormat{
    case Thumbnail
    case Normal
}

var CurrUser : FancyUser = FancyUser()

class FancyRestApi{

    let baseUrl = "http://api.fancyswap.com/rest/1.0/"
    let baseImageUrl = "http://beta.fancyswap.com/images/data/"
    var baseGeocodeUrl = "https://maps.googleapis.com/maps/api/geocode/json?"
    var googleKey = "AIzaSyA6JdmGCUjaROekUFBSTi6bZ34zsbe9_UI"
    let itemsPerPage = 20
    
    func GetItemsPerPage() -> Int
    {
        return itemsPerPage
    }
    
    ///Get url of an image.
    ///
    ///:param: name image filename with extension
    ///:param: size ajust url location based on required image size
    ///:returns: NSURL
    func imageURL(name:String, size:ImageFormat = ImageFormat.Thumbnail) -> NSURL {
        if size == ImageFormat.Normal {
            return NSURL(string: "\(baseImageUrl)images/\(name)")!
        }
        
        return NSURL(string: "\(baseImageUrl)thumbs/\(name)")!
    }
    

    ///Fetch a page item list asynchronously
    ///
    ///:param: page page number to fetch (zero based)
    ///:param: complete callback function called when task is completed, will run on the main thread
    ///:param: items array of FancyItem objects from the list, images are not loaded
    func GetItemList(page:Int, complete:(pageIndex: Int, succeeded:Bool, msg:String, items:[FancyItem]?) -> ()) {
        let offset = page * itemsPerPage
        get(baseUrl + "items?limit=\(itemsPerPage)&offset=\(offset)")
        {
            (url:String, succeeded: Bool, msg: String, retVal: NSDictionary) -> () in
            let range = url.rangeOfString("&offset=")
            let index = url[range!.endIndex..<url.endIndex].toInt()! / self.itemsPerPage
            
            if(succeeded) {
                if retVal["status"] as Bool {
                    var fis: [FancyItem] = []
                    
                    for itemDesc in (retVal["items"] as NSArray)
                    {
                        let fi:FancyItem = FancyItem(dic:(itemDesc as NSDictionary))
                        
                        fis.append(fi)
                    }
                    
                    
                    dispatch_async(dispatch_get_main_queue(), {
                        complete(pageIndex:index, succeeded: true, msg: msg, items:fis)
                    })
                }
                else {
                    dispatch_async(dispatch_get_main_queue(), {
                        complete(pageIndex:index, succeeded: false, msg: retVal["message"] as NSString, items:nil)
                    })
                }
            }
            else {
                dispatch_async(dispatch_get_main_queue(), {
                    complete(pageIndex:index, succeeded: false, msg: msg, items:nil)
                })
            }
        }
    }
    
    ///Fetch an item details
    ///
    ///Added details:
    /// - username: poster username
    /// - images: multiple images of the item
    ///
    ///:param: itemId item id
    ///:param: complete callback function called when task is completed, will fun on the main thread
    ///:param: item FancyItem object containing the details
    func GetItemDetail(itemId:Int, complete:(succeeded:Bool, msg:String, item:FancyItem?) -> ()) {

        get(baseUrl + "items/\(itemId)")
            {
                (url: String, succeeded: Bool, msg: String, retVal: NSDictionary) -> () in
                if(succeeded) {
                    if retVal["status"] as Bool {
                        var fi: FancyItem = FancyItem(dic:(retVal["item"] as NSDictionary))
                        
                        dispatch_async(dispatch_get_main_queue(), {
                            complete(succeeded: true, msg: msg, item:fi)
                        })
                        
                    }
                    else {
                        dispatch_async(dispatch_get_main_queue(), {
                            complete(succeeded: false, msg: retVal["message"] as NSString, item:nil)
                        })
                    }
                }
                else {
                    dispatch_async(dispatch_get_main_queue(), {
                        complete(succeeded: false, msg: msg, item:nil)
                    })
                }
        }
    }
    
    func GetUserDat(complete:(succeeded:Bool, msg:String, item:FancyUser?) -> ()) {

        if fancy_un.isEmpty || fancy_pw.isEmpty {
            complete(succeeded: false, msg: "login", item:nil)
            return
        }
       
        post(["email":fancy_un, "password":fancy_pw], url: "\(baseUrl)login")
            {
                (succeeded: Bool, msg: String, retVal: NSDictionary) -> () in
                if(succeeded) {
                    if retVal["status"] as Bool {
                        let fu: FancyUser = FancyUser(dic:(retVal["user"] as NSDictionary))
                        
                        dispatch_async(dispatch_get_main_queue(), {
                            complete(succeeded: true, msg: msg, item:fu)
                        })
                        
                    }
                    else {
                        dispatch_async(dispatch_get_main_queue(), {
                            complete(succeeded: false, msg: retVal["message"] as NSString, item:nil)
                        })
                    }
                }
                else {
                    dispatch_async(dispatch_get_main_queue(), {
                        complete(succeeded: false, msg: msg, item:nil)
                    })
                }
        }
        
    }
    
    ///Get address from Google Geocode
    ///
    ///:param: zip base value used to query address
    ///:returns: FancyAddress with zip, city, state & country
    func GetAddressFromZip(zip:String, completed:(succeeded:Bool, msg:String, data:FancyAddress?) -> Void) {
        let url = "\(baseGeocodeUrl)address=\(zip.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())!)&key=\(googleKey)"
        
        get(url)
            {
                (url:String, succeeded: Bool, msg: String, retVal: NSDictionary) -> () in
                if(succeeded) {
                    let status = (retVal["status"] as String).uppercaseString
                    if status == "OK" {
                        var addr: FancyAddress = FancyAddress()

                        addr = FancyAddress(swiftyDic:JSON(retVal))
                        
                        dispatch_async(dispatch_get_main_queue(), {
                            completed(succeeded: true, msg: msg, data:addr)
                        })
                        
                    }
                    else {
                        dispatch_async(dispatch_get_main_queue(), {
                            completed(succeeded: false, msg: status, data:nil)
                        })
                    }
                }
                else {
                    dispatch_async(dispatch_get_main_queue(), {
                        completed(succeeded: false, msg: msg, data:nil)
                    })
                }
        }
  
    }

    ///Fetch data from a url
    ///
    ///:param: url NSURL
    ///:param: index transfer needed data from the callee to the callback
    ///:param: complete callback function called when task is completed, will fun on the main thread
    ///:param: data NSDatar
    func GetDataFromUrl(url:NSURL, completed:(url:String, succeeded:Bool, msg:String, data:NSData?) -> Void) {
        
        var request = NSMutableURLRequest(URL: url)
        var session = NSURLSession.sharedSession()
        request.HTTPMethod = "GET"

        var task = session.dataTaskWithRequest(request, completionHandler:
            {
                data, response, error -> Void in
                
                if response == nil{
                    completed(url: request.URL!.absoluteString!, succeeded: false, msg: error!.localizedDescription, data: nil)
                    return
                }

                var err: NSError?
                var msg = "No message"
                let httpResponse = response as NSHTTPURLResponse
                let reqUrl = httpResponse.URL!.absoluteString! as String
                
                if(err != nil) {
                    dispatch_async(dispatch_get_main_queue(), {
                        completed(url: reqUrl, succeeded: false, msg: err!.localizedDescription, data: nil)
                    })
                }
                else {

                    //sleep(2)
                    
                    if httpResponse.statusCode != 200 {
                        dispatch_async(dispatch_get_main_queue(), {
                            completed(url: reqUrl, succeeded: false, msg: "Status code: \(httpResponse.statusCode)", data:data)
                        })
                    }
                    else {
                        dispatch_async(dispatch_get_main_queue(), {
                            completed(url: reqUrl, succeeded: true, msg: "", data:data)
                        })
                    }
                }
            }
        )
        task.resume()
    }
    
    ///commit an item order for the current loggin user (id by token).
    ///persist delivery address in DB
    ///
    ///:param: item ordered item
    func CommitOrder(item: FancyItem, completed:(succeeded:Bool, msg:String, order:FancyOrder?) -> Void) {
        var dic = Dictionary<String, String>()
        dic.updateValue("\(item.id)", forKey: "itemId")
        dic.updateValue("\(CurrUser.firstname)", forKey: "firstname")
        dic.updateValue("\(CurrUser.lastname)", forKey: "lastname")
        dic.updateValue("\(CurrUser.address)", forKey: "address")
        dic.updateValue("\(CurrUser.zip)", forKey: "zip")
        dic.updateValue("\(CurrUser.city)", forKey: "city")
        dic.updateValue("\(CurrUser.country)", forKey: "country")
        dic.updateValue("\(CurrUser.province)", forKey: "state")

    
        post(dic, url: baseUrl + "order")
            {
                (succeeded: Bool, msg: String, data: NSDictionary) -> () in
                if(succeeded) {
                    if data["status"] as Bool {
                        var order = FancyOrder()
                        
                        for (key, value) in data as NSDictionary
                        {
                            if key as String == "order"
                            {
                                order = FancyOrder(dic:(value as NSDictionary))
                                break
                            }
                        }
                        
                        dispatch_async(dispatch_get_main_queue(), {
                            completed(succeeded: true, msg: msg, order:order)
                        })
                        
                    }
                    else {
                        dispatch_async(dispatch_get_main_queue(), {
                            completed(succeeded: false, msg: data["message"] as NSString, order:nil)
                        })
                    }
                }
                else {
                    dispatch_async(dispatch_get_main_queue(), {
                        completed(succeeded: false, msg: msg, order:nil)
                    })
                }
        }
    }
    
    ///Post JSon content
    ///
    ///:param: params Dictinary of strings, used as json content in the post
    ///:param: url NSURL
    ///:param: completed callback function called when task is completed
    ///:param: retData returned JSon content in NSDictionary
    func post(params : Dictionary<String, String>, url : String, completed : (succeeded: Bool, msg: String, retData: NSDictionary) -> ()) {
        var request = NSMutableURLRequest(URL: NSURL(string: url)!)
        var session = NSURLSession.sharedSession()
        request.HTTPMethod = "POST"
        
        var err: NSError?
        if !Authentification.getToken().isEmpty
        {
            request.addValue(Authentification.getToken(), forHTTPHeaderField: "Authorization")
        }
        request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")
        
        var task = session.dataTaskWithRequest(request, completionHandler:
            {
                data, response, error -> Void in
                
                var err: NSError? = error
                if response == nil{
                    completed(succeeded: false, msg: err!.localizedDescription, retData: NSDictionary())
                    return
                }
                let httpResponse = response as NSHTTPURLResponse
                let reqUrl = httpResponse.URL!.absoluteString! as String
                var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
                
                var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
                
                if(err != nil) {
                    let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
                    completed(succeeded: false, msg: err!.localizedDescription, retData: NSDictionary())
                }
                else if let parseJSON = json {
                    completed(succeeded: true, msg: reqUrl, retData:parseJSON)
                }
                else {
                    // Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
                    let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
                    completed(succeeded: false, msg: "JSon deserialization error", retData: NSDictionary())
                }
            }
        )
        task.resume()
    }
    ///Get JSon content from url
    ///
    ///:param: url NSURL
    ///:param: completed callback function called when task is completed
    ///:param: retData returned JSon content in NSDictionary
    func get(url : String, completed : (url:String, succeeded: Bool, msg: String, retData: NSDictionary) -> ()) {
        var request = NSMutableURLRequest(URL: NSURL(string: url)!)
        var session = NSURLSession.sharedSession()
        request.HTTPMethod = "GET"
        
        var err: NSError?
        if !Authentification.getToken().isEmpty
        {
            request.addValue(Authentification.getToken(), forHTTPHeaderField: "Authorization")
        }
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")

        var task = session.dataTaskWithRequest(request, completionHandler:
            {
                data, response, error -> Void in

                var err: NSError? = error
                if response == nil{
                    completed(url:request.URL!.absoluteString!, succeeded: false, msg: err!.localizedDescription, retData: NSDictionary())
                    return
                }
                let httpResponse = response as NSHTTPURLResponse
                let reqUrl = httpResponse.URL!.absoluteString! as String
                var strData = NSString(data: data, encoding: NSUTF8StringEncoding)

                var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
                
                if(err != nil) {
                    let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
                    completed(url:reqUrl, succeeded: false, msg: err!.localizedDescription, retData: NSDictionary())
                }
                else if let parseJSON = json {
                    completed(url:reqUrl, succeeded: true, msg: reqUrl, retData:parseJSON)
                }
                else {
                    let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
                    completed(url:reqUrl, succeeded: false, msg: "JSon deserialization error", retData: NSDictionary())
                }
            }
        )
        task.resume()
    }
}
